<?php
class CodeGenerator implements ICodeGenerator {
	
	const FLOW_IF = 'if';
	const FLOW_FOREACH = 'foreach';
	
	var $elements = array();
	var $flowStack = array();
	
	/**
	 * The options for generating and outputting the PHP code
	 *
	 * @var CodeGeneratorOptions
	 */
	var $options = null;
	
	public function __construct(CodeGeneratorOptions $options = null) {
		
		if (! $options)
			$options = new CodeGeneratorOptions();
			
		$this->options = $options;
	}
	
	public function appendValueAssignment($var, $value, $type = self::ASSIGN_NORMAL) {
		
		switch ($type) {
			case self::ASSIGN_NORMAL:
				$this->write("$$var = " . var_export($value, true) . ';');
				break;
				
			case self::ASSIGN_APPEND_TEXT:
				$this->write("$$var .= " . var_export($value, true) . ';');
				break;
		}
	}
	
	public function appendEcho($value) {
		$this->write('echo ' . var_export($value, true) . ';');
	}
	
	public function appendIf($condition) {
		array_push($this->flowStack, self::FLOW_IF);
		$this->write("if ($condition) {", self::STYLE_INDENT);
	}
	
	public function appendElse($ifCondition = null) {
		
		$top = array_pop($this->flowStack);
		
		if ($top == self::FLOW_IF) {
			// put it back on the stack
			array_push($this->flowStack, $top);
			
			if ($ifCondition === null) {
				$this->write('} else {', self::STYLE_INDENT | self::STYLE_DEDENT);
			} else {
				$this->write("} elseif ($ifCondition) {", self::STYLE_INDENT | self::STYLE_DEDENT);
			}
		}
	}
	
	public function appendEndIf() {
		$this->appendEnd(self::FLOW_IF);
	}
	
	public function appendForeach($condition) {
		array_push($this->flowStack, self::FLOW_FOREACH);
		$this->write("foreach ($condition) {", self::STYLE_INDENT);
	}
	
	public function appendEndForeach() {
		$this->appendEnd(self::FLOW_FOREACH);
	}
	
	private function appendEnd($flowElement) {
		$top = array_pop($this->flowStack);
		
		if ($flowElement == $top) {
			$this->write('}', self::STYLE_DEDENT);
		} else {
			throw new Exception("Invalid");
		}
	}
	
	public function appendCustomCode($code, $style = null) {
		$this->write($code, $style);
	}
	
	public function write($code, $style = null) {
		$this->elements[] = array($code, $style);
	}
	
	public function output() {
		
		$output = '';
		
		if ($this->options->includeStartEndTags)
			$output .= '<?php' . $this->options->lineEnding;
		
		$indentLevel = $this->options->indentLevel;
		
		foreach ($this->elements as $element) {
			$code = $element[0];
			$style = $element[1];
			
			if ((($style & self::STYLE_DEDENT) == self::STYLE_DEDENT) && $indentLevel > 0)
				$indentLevel--;
			
			$indent = str_repeat($this->options->indentText, $indentLevel);
			$code = $indent . str_replace("\n", "\n" . $indent, $code);
				
			$output .= $code . $this->options->lineEnding;
			
			if (($style & self::STYLE_INDENT) == self::STYLE_INDENT)
				$indentLevel++;
		}
		
		return $output;
	}
}
?>